package com.nariano.server.domain.entities;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.springframework.util.Assert;

/**
 * Aggregate to Area or City, should not leak
 *
 */
class PopulationEntry implements Serializable {
	
	final Integer user; 

	List<Population> pops = new LinkedList<Population>();

	public PopulationEntry(Integer user) {
		Assert.notNull(user);
		this.user = user;
	}
	
	public PopulationEntry(Integer user, Collection<Population> pops) {
		Assert.notNull(user);
		this.user = user;
		this.pops.addAll(pops);
	}

	public Integer getUserId() {
		return user;
	}
	
	public int getCount() {
		int count = 0;
		for (Population p : pops) {
			count += p.getNumber();
		}
		return count;
	}

	public void addPopulation(Population p) {
		Assert.isTrue(this.user.equals(p.getUserId()));
		if (p.getNumber()==0) { return; }
		
		for (Population pp : pops) {
			if (pp.type().equals(p.type())) {
				pp.setNumber(pp.getNumber()+p.getNumber());
				return;
			}
		}
		pops.add(p);
	}

	public Population moveOutRandomPopulation() {
		Assert.isTrue(pops.size()>0);
		Population randomPop = peekRandomPopulation();
		
		Population res = new Population(randomPop.getUserId(), randomPop.type());
		res.setNumber(1);
		randomPop.setNumber(randomPop.getNumber()-1);
		if (randomPop.getNumber()<=0) {
			pops.remove(0);
		}
		return res;
	}

	public Collection<Population> getPopulations() {
		return Collections.unmodifiableCollection(pops);
	}

	@Override
	public String toString() {
		return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
	}

	public Population peekRandomPopulation() {
		// TODO real randomness
		if (pops.isEmpty()) { return null; }
		return pops.iterator().next();
	}

	public boolean cleanOutZeroes() {
		if (containZeros()) {
			List<Population> pops = new LinkedList<Population>();
			for(Population p : this.pops) {
				Assert.isNull(p.getPositionArea(),"Is in a city, but refer to an area");
				if (p.getNumber()>0) {
					pops.add(p);
				}
			}
			return true;
		}
		else {
			return false;
		}
	}

	public boolean containZeros() {
		for(Population p : pops) {
			if (p.getNumber()==0) {
				return true;
			}
		}
		return false;
	}

	public Population moveOutAllPopulations(PopulationType type) {
		for(Population p : pops) {
			if (p.type().equals(type)) {
				Population movedOut = new Population(this.user, type, p.getNumber());
				p.setNumber(0);		
				return movedOut ;
				
			}
		}
		return new Population(user, type);
	}

	
}
